/*
 * @ : Copyright (c) 2021 Phytium Information Technology, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0.
 *
 * @Date: 2021-04-07 09:53:07
 * @LastEditTime: 2021-07-07 17:55:12
 * @Description:  This files is for uart irq functions
 *
 * @Modify History:
 *  Ver   Who        Date         Changes
 * ----- ------     --------    --------------------------------------
 */

#include "pl011_uart.h"

extern u32 Pl011SendBuffer(Pl011 *uart_p);
extern u32 Pl011ReceiveBuffer(Pl011 *uart_p);

static void Pl011ReceiveErrorHandler(Pl011 *uart_p, u32 InterruptStatus);
static void Pl011ReceiveDataHandler(Pl011 *uart_p);
static void Pl011ReceiveTimeoutHandler(Pl011 *uart_p);
static void Pl011SendDataHandler(Pl011 *uart_p, u32 InterruptStatus);

/**
 * @name: Pl011GetInterruptMask
 * @msg:  此函数获取所有串口中断的mask。
 * @param {Ft_Uart} *uart_p
 * @return {u32} mask
 */
u32 Pl011GetInterruptMask(Pl011 *uart_p)
{
    FT_ASSERTNONVOID(uart_p != NULL);
    return FT_UART_READREG32(uart_p->config.base_address, UARTIMSC_OFFSET);
}

/**
 * @name:
 * @msg:
 * @param {Ft_Uart} *UartPtr
 * @param {u32} Mask
 * @return {*}
 */
void Pl011SetInterruptMask(Pl011 *UartPtr, u32 Mask)
{
    u32 temp_mask = Mask;
    FT_ASSERTVOID(UartPtr != NULL);

    temp_mask &= UARTIMSC_ALLM;

    FT_UART_WRITEREG32(UartPtr->config.base_address, UARTIMSC_OFFSET, temp_mask);
}

/**
 * @name: Pl011SetHandler
 * @msg:  设置中断回调函数
 * @param {*}
 * @return {*}
 */
void Pl011SetHandler(Pl011 *UartPtr, Pl011EventHandler fun_p,
                     void *Args)
{
    FT_ASSERTVOID(UartPtr != NULL);
    FT_ASSERTVOID(fun_p != NULL);
    FT_ASSERTVOID(UartPtr->is_ready == FT_COMPONENT_IS_READY);

    UartPtr->handler = fun_p;
    UartPtr->args = Args;
}

/**
 * @name: Pl011InterruptHandler
 * @msg:  串口中断函数入口
 * @param {Ft_Uart} *UartPtr
 * @return {*}
 */
void Pl011InterruptHandler(Pl011 *uart_p)
{
    u32 RegValue = 0;
    FT_ASSERTVOID(uart_p != NULL);
    FT_ASSERTVOID(uart_p->is_ready == FT_COMPONENT_IS_READY);

    RegValue = FT_UART_READREG32(uart_p->config.base_address, UARTIMSC_OFFSET);
    RegValue &= FT_UART_READREG32(uart_p->config.base_address, UARTMIS_OFFSET);

    if ((RegValue & ((u32)UARTMIS_RXMIS)) != (u32)0)
    {
        /* Received data interrupt */
        Pl011ReceiveDataHandler(uart_p);
    }

    if ((RegValue & ((u32)UARTMIS_TXMIS)) != (u32)0)
    {
        /* Transmit data interrupt */
        Pl011SendDataHandler(uart_p, RegValue);
    }

    if (((RegValue) & ((u32)UARTMIS_OEMIS | (u32)UARTMIS_BEMIS | (u32)UARTMIS_PEMIS | (u32)UARTMIS_FEMIS)) != (u32)0)
    {
        /* Received Error Status interrupt */
        Pl011ReceiveErrorHandler(uart_p, RegValue);
    }

    if ((RegValue & ((u32)UARTMIS_RTMIS)) != (u32)0)
    {
        /* Received Timeout interrupt */
        Pl011ReceiveTimeoutHandler(uart_p);
    }

    if (((RegValue) & ((u32)UARTMIS_DSRMMIS | (u32)UARTMIS_DCDMMIS | (u32)UARTMIS_CTSMMIS | (u32)UARTMIS_RIMMIS)) != (u32)0)
    {
        /* Modem status interrupt */
    }

    /* Clear the interrupt status. */
    FT_UART_WRITEREG32(uart_p->config.base_address, UARTICR_OFFSET,
                       RegValue);
}

static void Pl011ReceiveErrorHandler(Pl011 *uart_p, u32 InterruptStatus)
{
    uart_p->rxbs_error = 0;

    if (((InterruptStatus) & ((u32)UARTMIS_OEMIS | (u32)UARTMIS_BEMIS | (u32)UARTMIS_PEMIS | (u32)UARTMIS_FEMIS)) != 0)
    {
        uart_p->rxbs_error = 1;
    }

    (void)Pl011ReceiveBuffer(uart_p);

    if (0 == uart_p->rxbs_error)
    {
        if (uart_p->handler)
        {
            uart_p->handler(uart_p->args, FUART_EVENT_RECV_ERROR, uart_p->receive_buffer.requested_bytes - uart_p->receive_buffer.remaining_bytes);
        }
    }
}

/**
 * @name: Pl011ReceiveDataHandler
 * @msg:
 * @param {*}
 * @return {*}
 */
static void Pl011ReceiveDataHandler(Pl011 *uart_p)
{
    if ((u32)0 != uart_p->receive_buffer.remaining_bytes)
    {
        (void)Pl011ReceiveBuffer(uart_p);
    }

    if ((u32)0 == uart_p->receive_buffer.remaining_bytes)
    {
        if (uart_p->handler)
        {
            uart_p->handler(uart_p->args, FUART_EVENT_RECV_DATA, uart_p->receive_buffer.requested_bytes - uart_p->receive_buffer.remaining_bytes);
        }
    }
}

static void Pl011ReceiveTimeoutHandler(Pl011 *uart_p)
{
    u32 Event;

    if ((u32)0 != uart_p->receive_buffer.remaining_bytes)
    {
        (void)Pl011ReceiveBuffer(uart_p);
    }

    if ((u32)0 == uart_p->receive_buffer.remaining_bytes)
    {
        Event = FUART_EVENT_RECV_TOUT;
    }
    else
    {
        Event = FUART_EVENT_RECV_DATA;
    }

    if (uart_p->handler)
    {
        uart_p->handler(uart_p->args, Event, uart_p->receive_buffer.requested_bytes - uart_p->receive_buffer.remaining_bytes);
    }
}

static void Pl011SendDataHandler(Pl011 *uart_p, u32 InterruptStatus)
{
    if (uart_p->send_buffer.remaining_bytes == (u32)0)
    {
        if (uart_p->handler)
        {
            uart_p->handler(uart_p->args, FUART_EVENT_RECV_DATA, uart_p->receive_buffer.requested_bytes - uart_p->receive_buffer.remaining_bytes);
        }
    }
    else if (InterruptStatus & UARTMIS_TXMIS)
    {
        Pl011SendBuffer(uart_p);
    }
    else
    {
    }
}
